// 通过SetDeadline实现超时判断
package main

import (
	"io"
	"loggor"
	"net"
	"time"
)

type allconn struct {
	client_conn *net.Conn
	server_conn *net.Conn
}

const (
	ip   = "0.0.0.0" //监听地址
	port = 11212     //监听端口
	address    = "" // 转发地址及端口
	headertime = 30 // 无操作超时等待时间（秒）
)

// var errclose = errors.New("use of closed network connection")
// var errtimeout = errors.New("i/o timeout")
var logg *loggor.Logger

func init() {
	logg = loggor.New()
	logg.SetType(3)                        //日志处理类型
	logg.SetRollingDaily("./", "conntest") // 日志存放位置，及文件名（不加后缀）
}

func Server(mlister *net.TCPListener) {
	for {
		conn, err := mlister.Accept()
		if err != nil {
			logg.Println("客户端请求连接异常")
			continue
		}
		new_conn := new(allconn)
		new_conn.client_conn = &conn
		// (*new_conn.client_conn).SetDeadline(time.Now().Add(headertime * time.Second))
		logg.Println("客户端IP地址:", conn.RemoteAddr().String())
		go new_conn.Forward()
	}
}

// 开启数据传输
func (a *allconn) Forward() {
	snet, err := net.Dial("tcp", address)
	logg.Println("连接后端IP地址:", snet.RemoteAddr().String())
	if err != nil {
		logg.Println("转发后端连接异常")
		return
	}
	a.server_conn = &snet

	go a.ClientCopy()
	a.ServerCopy()
	logg.Println((*a.client_conn).RemoteAddr().String(), "连接传输结束")
}

func (a *allconn) ClientCopy() {
	size := 1024
	buf := make([]byte, size)
	for {
		(*a.client_conn).SetDeadline(time.Now().Add(headertime * time.Second))
		nr, er := (*a.client_conn).Read(buf)
		(*a.client_conn).SetDeadline(time.Time{})
		if nr > 0 {
			nw, ew := (*a.server_conn).Write(buf[0:nr]) // nw写入的数据量
			if ew != nil {
				logg.Println((*a.server_conn).RemoteAddr().String(), "内容写入异常")
				a.Close()
				break
			}
			if nr != nw {
				// err = io.ErrShortWrite // 写入操作写入的数据比提供的少，却没有显式的返回错误。
				logg.Println((*a.server_conn).RemoteAddr().String(), "内容写入缺失")
				a.Close()
				break
			}
		}
		if er != nil {
			if er == io.EOF {
				logg.Println((*a.client_conn).RemoteAddr().String(), "正常结束")
				break
			}
			a.Close()
			logg.Println((*a.client_conn).RemoteAddr().String(), "发生异常: ", er, " 连接结束")
			break
		}
	}
}

func (a *allconn) ServerCopy() {
	size := 1024
	buf := make([]byte, size)
	for {
		nr, er := (*a.server_conn).Read(buf)
		if nr > 0 {
			nw, ew := (*a.client_conn).Write(buf[0:nr]) // nw写入的数据量
			if ew != nil {
				logg.Println((*a.client_conn).RemoteAddr().String(), "内容写入异常")
				break
			}
			if nr != nw {
				// err = io.ErrShortWrite // 写入操作写入的数据比提供的少，却没有显式的返回错误。
				logg.Println((*a.client_conn).RemoteAddr().String(), "内容写入缺失")
				break
			}
		}
		if er != nil {
			if er == io.EOF {
				logg.Println((*a.server_conn).RemoteAddr().String(), "正常结束")
				break
			}
			a.Close()
			logg.Println((*a.server_conn).RemoteAddr().String(), "发生异常: ", er, " 连接结束")
			break
		}

	}
}

func (a *allconn) Close() {
	(*a.client_conn).Close()
	(*a.server_conn).Close()
}

func main() {
	// listenAddr, err := net.ResolveTCPAddr("tcp", listenAddrString)
	// listen, err := net.ListenTCP("tcp", listenAddr)
	listen, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP(ip), port, ""})
	if err != nil {
		logg.Println("监听端口失败:", err.Error())
		return
	}
	logg.Println("已初始化连接，等待客户端连接...")
	Server(listen)
}


// 通过指针完成超时判断
package main

import (
	"io"
	"loggor"
	"net"
	"time"
)

const (
	ip         = "0.0.0.0"                                            //监听地址
	port       = 11211                                                //监听端口
	address    = "" // 转发地址及端口
	headertime = 3600                                                 // 无操作超时等待时间（秒）
)

var logg *loggor.Logger

func init() {
	logg = loggor.New()
	logg.SetType(3)                       //日志处理类型
	logg.SetRollingDaily("./", "connect") // 日志存放位置，及文件名（不加后缀）
}

func Server(mlister *net.TCPListener) {
	for {
		conn, err := mlister.AcceptTCP()
		if err != nil {
			logg.Println("客户端请求连接异常")
			continue
		}
		logg.Println("客户端IP地址:", conn.RemoteAddr().String())
		go Forward(conn)
	}
}

// 开启数据传输
func Forward(mnet net.Conn) {
	snet, err := net.Dial("tcp", address)
	logg.Println("连接后端IP地址:", snet.RemoteAddr().String())
	// headerchan := make(chan int, 1)
	if err != nil {
		logg.Println("转发后端连接异常")
		return
	}
	headerchan := make(chan int, 1)
	timechannls := make(chan int, 1)
	go timeOutJudge(mnet, timechannls)
	go EachCopy(mnet, snet, headerchan, timechannls)
	EachCopy(snet, mnet, headerchan, timechannls)
	logg.Println(mnet.RemoteAddr().String(), "连接传输结束")
}

func EachCopy(mconn net.Conn, sconn net.Conn, headerchan chan int, timechannls chan int) {
	size := 1024
	buf := make([]byte, size)

	for {
		select {
		case <-headerchan:
			mconn.Close()
			sconn.Close()
			goto Loop
		default:
			nr, er := mconn.Read(buf)
			if nr > 0 {
				timechannls <- 1
				nw, ew := sconn.Write(buf[0:nr]) // nw写入的数据量
				if ew != nil {
					logg.Println(sconn.RemoteAddr().String(), "内容写入异常")
					headerchan <- 1
					timechannls <- 2
					break
				}
				if nr != nw {
					// err = io.ErrShortWrite // 写入操作写入的数据比提供的少，却没有显式的返回错误。
					logg.Println(sconn.RemoteAddr().String(), "内容写入缺失")
					headerchan <- 1
					timechannls <- 2
					break
				}
			}
			if er != nil {
				if er == io.EOF {
					logg.Println(mconn.RemoteAddr().String(), "正常结束")
					headerchan <- 1
					timechannls <- 2
					break
				}
				headerchan <- 1
				timechannls <- 2
				logg.Println(mconn.RemoteAddr().String(), "发生异常: ", er, " 连接结束")
			}
		}
	}
Loop:
	return
}

func timeOutJudge(mconn net.Conn, readChannel chan int) {
	for {
		select {
		case a := <-readChannel:
			if a == 2 {
				goto Loop
			}
			continue
		case <-time.After(time.Second * time.Duration(headertime)):
			mconn.Close()
			logg.Println(mconn.RemoteAddr().String(), "连接超时，主动关闭相关线程及连接")
			goto Loop
		}
	}
Loop:
	return
}

func main() {
	// listenAddr, err := net.ResolveTCPAddr("tcp", listenAddrString)
	// listen, err := net.ListenTCP("tcp", listenAddr)
	listen, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP(ip), port, ""})
	if err != nil {
		logg.Println("监听端口失败:", err.Error())
		return
	}
	logg.Println("已初始化连接，等待客户端连接...")
	Server(listen)
}